/*
 * ProductHClass.java
 *
 * Created on December 10, 2007, 10:57 PM
 *
 */
package org.osdtsystem.hierarchy;

import java.util.Arrays;

/**
 * A hierarchy class in a product hierarchy.
 * @author Martin Haulrich and Matthias Buch-Kromann
 */
public final class ProductHClass extends AbstractHClass {
    private final HClass[] hclasses;
    private final int hash;
    private final int depth;

    /** 
     * Construct a product class.
     * @param hclasses the component classes in the product class
     * @param depth the depth of the product class (ignored if the depth is negative)
     */
    ProductHClass(final HClass[] hclasses, int depth) {
        this.hclasses = Arrays.copyOf(hclasses, hclasses.length);
        this.hash = this.hclasses.hashCode();

        // Recompute depth if current depth is negative, otherwise trust it
        if (depth >= 0) {
            this.depth = depth;
        } else {
            // Compute depth
            int newdepth = 0;
            for (HClass hc : hclasses) {
                newdepth += hc.depth();
            }
            this.depth = newdepth;
        }
    }

    /**
     * Construct a product class.
     * @param hclasses the component classes in the product class.
     */
    ProductHClass(final HClass[] hclasses) {
        this(hclasses, -1);
    }

    public HClass hclass(int i) {
        return hclasses[i];
    }

    public <H extends HClass> H component(Class<H> hclassType, int i) {
        HClass hclass = hclasses[i];
        if (hclassType.isInstance(hclass))
            return hclassType.cast(hclass);
        else
            throw new IllegalArgumentException("Component class "
                    + i + " in class  " + this + "is not an instance of the expected hclass type "
                    + hclassType);
    }

    @Override
    public int depth() {
        return depth;
    }

    @Override
    public int hashCode() {
        return hash;
    }

    @Override
    public boolean equals(Object that) {
        if (that == null) {
            return false;
        }
        if (getClass() != that.getClass()) {
            return false;
        }
        final ProductHClass other = (ProductHClass) that;
        if (this.hash != other.hash) {
            return false;
        }
        if (this.hclasses != other.hclasses && (this.hclasses == null 
                || ! Arrays.equals(this.hclasses,other.hclasses))) {
            return false;
        }
        return true;
    }
}
